// SPDX-License-Identifier: GPL-2.0 or GPL-3.0
// Copyright © 2018-2019 Ariadne Devos

/* sHT -- (arm) compare values without misinforming the compiler

  Derived from x86 <sHT/test-arch.h>. */

#ifndef _sHT_ARCH_TEST
#define _sHT_ARCH_TEST

/* Operand order: as in mathematics (%0,%1: %0 op %1)
  Test instruction: cmp/tst followed by b$CONDITION
    (cmp/tst sets instruction code, b$CONDITION does the branch.
    Many instructions in ARM can be made conditional by appending
    the condition.)

  Sign issues: { unsigned: higher / lower, signed: greater / lower }
  Immediates: #$NUMBER

  % modifier (GCC): commutative
    (e.g. equality, intersection, union)
    (NOT <, >). */

#define _sHT_eq(a, b, correct) \
	__asm__ goto ("cmp %0,%1;beq %l[" #correct "]" : : "%r" (a), "rI" (b) : "cc" : correct)
#define _sHT_neq(a, b, correct) \
	__asm__ goto ("cmp %0,%1;bne %l[" #correct "]" : : "%r" (a), "rI" (b) : "cc" : correct)
#define _sHT_gt(a, b, correct) \
	__asm__ goto ("cmp %0,%1;bhi %l[" #correct "]" : : "r" (a), "rI" (b) : "cc" : correct)
#define _sHT_ge(a, b, correct) \
	__asm__ goto ("cmp %0,%1;bhs %l[" #correct "]" : : "r" (a), "rI" (b) : "cc" : correct)
#define _sHT_lt(a, b, correct) \
	__asm__ goto ("cmp %0,%1;blo %l[" #correct "]" : : "r" (a), "rI" (b) : "cc" : correct)
#define _sHT_and_any_p(a, b, correct) \
	__asm__ goto ("tst %0,%1;bne %l[" #correct "]" : : "%r" (a), "rI" (b) : "cc" : correct)
#define _sHT_and_none_p(a, b, correct) \
	__asm__ goto ("tst %0,%1;beq %l[" #correct "]" : : "%r" (a), "rI" (b) : "cc" : correct)
#define _sHT_zero_p(a, correct) \
	__asm__ goto ("cmp %0,#0;beq %l[" #correct "]" : : "r" (a) : "cc" : correct)
#define _sHT_nonzero_p(a, correct) \
	__asm__ goto ("cmp %0,#0;bne %l[" #correct "]" : : "r" (a) : "cc" : correct)
#define _sHT_lt0(a, correct) \
	__asm__ goto ("tst %0,%0;bmi %l[" #correct "]" : : "r" (a) : "cc" : correct)

/* Code generated by GCC */
#define _sHT_msb_set(a, correct) \
	__asm__ goto ("cmp %0,#0;blt %l[" #correct "]" : : "r" (a) : "cc" : correct)
#define _sHT_msb_unset(a, correct) \
	__asm__ goto ("cmp %0,#0;bge %l[" #correct "]" : : "r" (a) : "cc" : correct)

/* TODO: GCC generates different code, more efficient? */
/* Operational semantics: ret <- 0. If a = b, ret <- 1.
  Functional semantics: ret <- a = b ? 1 : 0. */
#define _sHT_eq_bool(a, b, ret) \
	do {	(ret) = 0; \
		__asm__("cmp %1,%2;moveq %0,#1" : "+r" (ret) : "r" (a), "rI" (b) : "cc"); \
	} while (0)

#endif
